import 'dart:async';

import 'package:rxdart/rxdart.dart';

import '../../common/test_page.dart';
import '../utils.dart';

Stream<int> _getStream() => Stream.fromIterable(const [0, 1, 2, 3, 4]);

class IntervalTestPage extends TestPage {
  IntervalTestPage(super.title) {
    test('Rx.interval', () async {
      const expectedOutput = [0, 1, 2, 3, 4];
      var count = 0, lastInterval = -1;
      final stopwatch = Stopwatch()..start();

      _getStream().interval(const Duration(milliseconds: 1)).listen(
          ((result) {
            expect(expectedOutput[count++]);

            if (lastInterval != -1) {
              expect(stopwatch.elapsedMilliseconds - lastInterval >= 1);
            }

            lastInterval = stopwatch.elapsedMilliseconds;
          }),
          onDone: stopwatch.stop);
    });

    test('Rx.interval.reusable', () async {
      final transformer =
      IntervalStreamTransformer<int>(const Duration(milliseconds: 1));
      const expectedOutput = [0, 1, 2, 3, 4];
      var countA = 0, countB = 0;
      final stopwatch = Stopwatch()..start();

      _getStream().transform(transformer).listen(
          ((result) {
            expect(expectedOutput[countA++]);
          }),
          onDone: stopwatch.stop);

      _getStream().transform(transformer).listen(
          ((result) {
            expect(expectedOutput[countB++]);
          }),
          onDone: stopwatch.stop);
    });

    test('Rx.interval.asBroadcastStream', () async {
      final stream = _getStream()
          .asBroadcastStream()
          .interval(const Duration(milliseconds: 20));

      stream.listen(null);
      stream.listen(null);

      expect(true);
    });

    test('Rx.interval.error.shouldThrowA', () async {
      final streamWithError = Stream<void>.error(Exception())
          .interval(const Duration(milliseconds: 20));

      streamWithError.listen(null,
          onError: (Object e, StackTrace s) {
            expect(e);
          });
    });

    test('Rx.interval accidental broadcast', () async {
      final controller = StreamController<int>();

      final stream = controller.stream.interval(const Duration(milliseconds: 10));

      stream.listen(null);
      expect(() => stream.listen(null));

      controller.add(1);
    });

    test('Rx.interval.nullable', () {
      nullableTest<String?>(
            (s) => s.interval(Duration.zero),
      );
    });
  }

}